from django.contrib.sites.managers import CurrentSiteManager
from django.contrib.sites.models   import Site
from django.core.exceptions        import ImproperlyConfigured,ObjectDoesNotExist
from django.db                     import models,transaction
from django.db.models              import Q
from sitepal.sitebase.converters   import to_string_callable,to_string_callables
from sitepal.sitebase.util         import get_superuser,iterappmodules
from sitepal.sitebase.validators   import validate_callable_object,validate_callable_objects

class TreeManager(models.Manager):
    def get_roots(self):
        return self.get_query_set().filter(parent__isnull=True)

class EntityManager(CurrentSiteManager):
    def get_query_set(self):
        from models import ORIGIN_UNKNOWN
        return super(EntityManager,self).get_query_set().filter(~Q(origin__exact=ORIGIN_UNKNOWN))

    def get_all_set(self):
        return super(EntityManager,self).get_query_set()

    def get_with_origin(self,model):
        return self.get_query_set().filter(origin__exact=model._meta.app_label)

    def get_with_user_origin(self):
        from models import ORIGIN_USER
        return self.get_query_set().filter(origin__exact=ORIGIN_USER)

    def get_for_owner(self,user):
        return self.get_query_set().filter(owned_by=user)

class UnknownEntityManager(CurrentSiteManager):
    def get_query_set(self):
        from models import ORIGIN_UNKNOWN
        return super(UnknownEntityManager,self).get_query_set().filter(origin__exact=ORIGIN_UNKNOWN)

class EntityTreeManager(EntityManager,TreeManager):
    pass

class ResourceManager(EntityManager):
    def get_by_name(self,name):
        self.get(name__exact=name)

    def itermodules(self):
        raise NotImplementedError

    def sync_prepare(self):
        from models import ORIGIN_USER,ORIGIN_UNKNOWN
        self.filter(~Q(origin__exact=ORIGIN_USER)).update(origin=ORIGIN_UNKNOWN)

    def sync_object(self,name,data):
        try:
            try:
                obj     = self.get_all_set().get(name__exact=name)
                created = False
            except ObjectDoesNotExist:
                obj       = self.model()
                obj.name  = name
                obj.site  = Site.objects.get_current()
                obj.owner = obj.creator = get_superuser()
                created   = True
            obj.origin = data['app_label']
            return created,obj
        except Exception,e:
            raise ImproperlyConfigured,e

    @transaction.commit_on_success
    def sync_database(self,submodule=None):
        itermodules = self.itermodules() if not submodule else iterappmodules(submodule)
        for app_label,module in itermodules:
            if hasattr(module,'definitions'):
                for name,data in module.definitions.iteritems():
                    data['app_label'] = app_label
                    created,obj       = self.sync_object(name,data)
                    obj.full_clean()
                    obj.save()

class ResourceTreeManager(ResourceManager,TreeManager):
    pass

class PropertyManager(ResourceManager):
    def itermodules(self):
        return iterappmodules(submodule='siteapp.properties')

    def sync_object(self,name,data):
        def to_callable_name(name):
            if name in data:
                value = data[name]
                validate_callable_object(value)
                return to_string_callable(value)
            return None
        def to_callable_names(name):
            if name in data:
                values = data[name]
                validate_callable_objects(values)
                return to_string_callables(values)
            return None

        created,obj = super(PropertyManager,self).sync_object(name,data)
        try:
            obj.value           = data['value']
            obj.to_python_name  = to_callable_name('to_python')
            obj.to_string_name  = to_callable_name('to_string')
            obj.validator_names = to_callable_names('validators')
            return created,obj
        except Exception,e:
            raise ImproperlyConfigured,e

